package com.atguigu.tingshu.album.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import com.atguigu.tingshu.album.mapper.*;
import com.atguigu.tingshu.album.service.AlbumInfoService;
import com.atguigu.tingshu.common.cache.GuiGuCache;
import com.atguigu.tingshu.common.constant.KafkaConstant;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.service.KafkaService;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.album.AlbumAttributeValue;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.AlbumStat;
import com.atguigu.tingshu.query.album.AlbumInfoQuery;
import com.atguigu.tingshu.vo.album.AlbumInfoVo;
import com.atguigu.tingshu.vo.album.AlbumListVo;
import com.atguigu.tingshu.vo.album.AlbumStatVo;
import com.atguigu.tingshu.vo.album.TrackStatMqVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.Nullable;
import org.redisson.api.RLock;


import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 相册信息服务
 *
 * @author ym
 * @date 2025/06/27 15:43
 */
@Slf4j
@Service
@SuppressWarnings({"all"})
public class AlbumInfoServiceImpl extends ServiceImpl<AlbumInfoMapper, AlbumInfo> implements AlbumInfoService {

    /**
     * 相册信息映射器
     */
    @Autowired
    private AlbumInfoMapper albumInfoMapper;
    /**
     * 专辑属性值映射器
     */
    @Autowired
    private TrackInfoMapper trackInfoMapper;
    @Autowired
    private AlbumAttributeValueMapper albumAttributeValueMapper;
    /**
     * 相册统计映射器
     */
    @Autowired
    private AlbumStatMapper albumStatMapper;
    /**
     * 卡夫卡服务
     */
    @Autowired
    KafkaService kafkaService;
    /**
     * redis模板
     */
    @Autowired
    private RedisTemplate redisTemplate;
    /**
     * 跟踪统计映射器
     */
    @Autowired
    private TrackStatMapper trackStatMapper;


    /**
     * 保存相册信息
     *
     * @param albumInfoVo 相册信息
     * @param userId      用户ID
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveAlbumInfo(AlbumInfoVo albumInfoVo, Long userId) {

        AlbumInfo albumInfo = BeanUtil.copyProperties(albumInfoVo, AlbumInfo.class);
        albumInfo.setUserId(userId);
        albumInfoMapper.insert(albumInfo);
        if (albumInfoVo.getTracksForFree() == null) {
            albumInfoVo.setTracksForFree(1);

        }
        //  设置专辑状态
        albumInfo.setStatus("0301");
        //  设置专辑属性值
        List<AlbumAttributeValue> valueVoList = albumInfo.getAlbumAttributeValueVoList();
        if (CollectionUtils.isEmpty(valueVoList)) {
            throw new GuiguException(400, "专辑属性不能为空");
        } else {
            for (AlbumAttributeValue valueVo : valueVoList) {

                valueVo.setAlbumId(albumInfo.getId());
                albumAttributeValueMapper.insert(valueVo);

            }
        }
        // 更新专辑信息
        this.saveAlbumStu(albumInfo.getId(), SystemConstant.ALBUM_STAT_PLAY, 0);
        this.saveAlbumStu(albumInfo.getId(), SystemConstant.ALBUM_STAT_SUBSCRIBE, 0);
        this.saveAlbumStu(albumInfo.getId(), SystemConstant.ALBUM_STAT_BUY, 0);
        this.saveAlbumStu(albumInfo.getId(), SystemConstant.ALBUM_STAT_COMMENT, 0);
        kafkaService.sendMessage(KafkaConstant.QUEUE_ALBUM_UPPER, albumInfo.getId().toString());

    }

    /**
     * 查找用户相册页面
     *
     * @param page           页面
     * @param limit          极限
     * @param albumInfoQuery 相册信息查询
     * @return {@link Page<AlbumListVo>}
     */
    @Override
    public Page<AlbumListVo> findUserAlbumPage(Integer page, Integer limit, AlbumInfoQuery albumInfoQuery) {
        Long userId = AuthContextHolder.getUserId();
        albumInfoQuery.setUserId(userId);
        Page<AlbumListVo> albumListVoPage = new Page<>(page, limit);
        albumListVoPage = albumInfoMapper.findUserAlbumPage(albumListVoPage, albumInfoQuery);
        return albumListVoPage;
    }

    /**
     * 删除相册信息
     *
     * @param id id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeAlbumInfo(Long id) {
        AlbumInfo albumInfo = albumInfoMapper.selectById(id);
        if (albumInfo == null || albumInfo.getIncludeTrackCount() > 0) {
            throw new GuiguException(400, "专辑下有声音，不能删除");
        }
        albumInfoMapper.deleteById(id);
        QueryWrapper<AlbumAttributeValue> albumId = new QueryWrapper<AlbumAttributeValue>().eq("album_id", id);
        albumAttributeValueMapper.delete(albumId);
        QueryWrapper<AlbumStat> albumId1 = new QueryWrapper<AlbumStat>().eq("album_id", id);
        albumStatMapper.delete(albumId1);
        kafkaService.sendMessage(KafkaConstant.QUEUE_ALBUM_LOWER, id.toString());
    }

    /**
     * 客户编辑
     */
    @Autowired
    private RedissonClient redissonClient;

    /**
     * 获取相册信息
     *
     * @param id id
     * @return {@link AlbumInfo}
     */
    @GuiGuCache(prefix = RedisConstant.ALBUM_INFO_PREFIX)
    @Override
    public AlbumInfo getAlbumInfo(Long id) {
        return getInfo(id);
//        return getalbumInfoRedission(id);
//        return getalbumInfoRedis(id);
    }

    /**
     * 使用redission整合
     *
     * @param id id
     * @return {@link AlbumInfo}
     */


    /**
     * 编号相册信息恢复
     *
     * @param id id
     * @return {@link AlbumInfo}
     */
    private AlbumInfo getalbumInfoRedission(Long id) {
        AlbumInfo albumInfo = null;
        try {
            //尝试查询redis缓存
            String datakey = RedisConstant.ALBUM_INFO_PREFIX + id;
            //尝试查询缓存
            albumInfo = (AlbumInfo) redisTemplate.opsForValue().get(datakey);
            if (albumInfo != null) {
                return albumInfo;
            }
            if (albumInfo == null) {
                //没有查询到数据,先尝试获取锁
                String lockValue = IdUtil.fastSimpleUUID();
                String lockkey = RedisConstant.ALBUM_LOCK_PREFIX + id;
                RLock lock = redissonClient.getLock(lockkey);
                try {
                    //使用redison获取锁

                    lock.lock();
                    albumInfo = (AlbumInfo) redisTemplate.opsForValue().get(datakey);
                    if (albumInfo != null) {
                        redisTemplate.opsForValue().set(datakey, albumInfo, RedisConstant.ALBUM_TEMPORARY_TIMEOUT, TimeUnit.SECONDS);
                        return albumInfo;

                    } else {
                        albumInfo = getInfo(id);
                        if (albumInfo == null) {
                            albumInfo = new AlbumInfo();
                            //防止缓存穿透
                            redisTemplate.opsForValue().set(datakey, albumInfo, RedisConstant.ALBUM_TEMPORARY_TIMEOUT, TimeUnit.SECONDS);
                            return albumInfo;
                        } else {
                            redisTemplate.opsForValue().set(datakey, albumInfo, RedisConstant.ALBUM_TEMPORARY_TIMEOUT, TimeUnit.SECONDS);
                            return albumInfo;


                        }

                    }
                } finally {
                    lock.unlock();
                }


            }
        } catch (Exception e) {
            e.printStackTrace();
            return albumInfo;
        }
        return albumInfo;
    }

    /**
     * 编号相册信息redis整合
     *
     * @param id id
     * @return {@link AlbumInfo}
     */
    private AlbumInfo getalbumInfoRedis(Long id) {
        //尝试查询redis缓存
        String datakey = RedisConstant.ALBUM_INFO_PREFIX + id;
        //尝试查询缓存
        AlbumInfo albumInfo = (AlbumInfo) redisTemplate.opsForValue().get(datakey);
        if (albumInfo != null) {
            return albumInfo;
        }
        if (albumInfo == null) {
            //没有查询到数据,先尝试获取锁
            String lockValue = IdUtil.fastSimpleUUID();
            String lockkey = RedisConstant.ALBUM_LOCK_PREFIX + id;
            //获取锁成功
            //设置锁过期时间
            Boolean lock = redisTemplate.opsForValue().setIfAbsent(lockkey, lockValue, RedisConstant.ALBUM_TEMPORARY_TIMEOUT, TimeUnit.SECONDS);
            try {
                if (Boolean.TRUE.equals(lock)) {
                    albumInfo = getInfo(id);
                    if (albumInfo == null) {
                        albumInfo = new AlbumInfo();
                        //防止缓存穿透
                        redisTemplate.opsForValue().set(datakey, albumInfo, RedisConstant.ALBUM_TEMPORARY_TIMEOUT, TimeUnit.SECONDS);
                        return albumInfo;
                    } else {
                        redisTemplate.opsForValue().set(datakey, albumInfo, RedisConstant.ALBUM_TEMPORARY_TIMEOUT, TimeUnit.SECONDS);
                        return albumInfo;


                    }

                } else {
                    //获取锁失败，等待重试
                    Thread.sleep(100);
                    return getAlbumInfo(id);
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } finally {
                //释放锁
                DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
                //设置脚本文本
                String script = "if redis.call(\"get\",KEYS[1]) == ARGV[1]\n" +
                        "then\n" +
                        "    return redis.call(\"del\",KEYS[1])\n" +
                        "else\n" +
                        "    return 0\n" +
                        "end";
                redisScript.setScriptText(script);
                redisScript.setResultType(Long.class);
                redisTemplate.execute(redisScript, List.of(lockkey), lockValue);
            }


        }
        return getInfo(id);
    }

    /**
     * 获取信息
     *
     * @param id id
     * @return {@link AlbumInfo}
     */
    @Nullable
    private AlbumInfo getInfo(Long id) {
        AlbumInfo albumInfo = albumInfoMapper.selectById(id);
        LambdaQueryWrapper<AlbumAttributeValue> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(AlbumAttributeValue::getAlbumId, id);
        if (albumInfo != null) {
            List<AlbumAttributeValue> albumAttributeValues = albumAttributeValueMapper.selectList(queryWrapper);
            albumInfo.setAlbumAttributeValueVoList(albumAttributeValues);
        }
        return albumInfo;
    }

    /**
     * 更新相册信息
     *
     * @param id          id
     * @param albumInfoVo 专辑信息vo
     * @param userId      用户id
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateAlbumInfo(Long id, AlbumInfoVo albumInfoVo, Long userId) {

        AlbumInfo albumInfo = BeanUtil.copyProperties(albumInfoVo, AlbumInfo.class);
        albumInfo.setUserId(userId);
        albumInfoMapper.updateById(albumInfo);
        QueryWrapper<AlbumAttributeValue> albumAttributeValueQueryWrapper = new QueryWrapper<>();
        albumAttributeValueQueryWrapper.eq("album_id", id);
        albumAttributeValueMapper.delete(albumAttributeValueQueryWrapper);
        List<AlbumAttributeValue> valueVoList = albumInfo.getAlbumAttributeValueVoList();
        if (CollectionUtils.isEmpty(valueVoList)) {
            throw new GuiguException(400, "专辑属性不能为空");
        } else {
            for (AlbumAttributeValue valueVo : valueVoList) {
                valueVo.setAlbumId(id);
                albumAttributeValueMapper.insert(valueVo);
            }
        }
        if (albumInfoVo.getIsOpen().equals(1)) {
            kafkaService.sendMessage(KafkaConstant.QUEUE_ALBUM_UPPER, albumInfo.getId().toString());
        } else {
            kafkaService.sendMessage(KafkaConstant.QUEUE_ALBUM_LOWER, albumInfo.getId().toString());
        }

    }

    /**
     * 查找用户所有专辑列表
     *
     * @param userId 用户ID
     * @return {@link List<AlbumInfo>}
     */
    @Override
    public List<AlbumInfo> findUserAllAlbumList(Long userId) {
        QueryWrapper<AlbumInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userId).orderByDesc("id").last("limit 5");
        return albumInfoMapper.selectList(queryWrapper);

    }

    /**
     * 获取专辑统计数据vo
     *
     * @param albumId 专辑ID
     * @return {@link AlbumStatVo}
     */

    @Override
    public AlbumStatVo getAlbumStatVo(Long albumId) {
        AlbumStatVo albumStatVo = albumStatMapper.getAlbumStatVo(albumId);
        return albumStatVo;
    }

    /**
     * 更新跟踪统计
     *
     * @param trackStatMqVo 跟踪统计mq in
     */
    @Override
    public void updateTrackStat(TrackStatMqVo trackStatMqVo) {
//用redis做幂等性处理
        String key = "mq" + trackStatMqVo.getBusinessNo();
        try {
            Boolean b = redisTemplate.opsForValue().setIfAbsent(key, trackStatMqVo.getBusinessNo(), 1, TimeUnit.HOURS);
            if (b) {
                //更新声音统计信息
                trackStatMapper.updateTrackStat(trackStatMqVo.getTrackId(), trackStatMqVo.getStatType(), trackStatMqVo.getCount());
                //更新专辑统计信息(专辑播放数)
                if (SystemConstant.TRACK_STAT_PLAY.equals(trackStatMqVo.getStatType())) {
                    albumStatMapper.updateAlbumStat(trackStatMqVo.getAlbumId(), SystemConstant.ALBUM_STAT_PLAY, trackStatMqVo.getCount());
                }
                if (SystemConstant.TRACK_STAT_COMMENT.equals(trackStatMqVo.getStatType())) {
                    albumStatMapper.updateAlbumStat(trackStatMqVo.getAlbumId(), SystemConstant.ALBUM_STAT_COMMENT, trackStatMqVo.getCount());
                }

            }
        } catch (Exception e) {
            redisTemplate.delete(key);
            throw new RuntimeException(e);
        }

    }

    @Override
    public AlbumInfo getAlbumInfobytrackId(Long id) {
        Long albumId = trackInfoMapper.selectById(id).getAlbumId();
        return getAlbumInfo(albumId);

    }

    /**
     * 保存相册stu
     *
     * @param id            id
     * @param albumStatPlay 专辑统计播放
     * @param i             我
     */
    private void saveAlbumStu(Long id, String albumStatPlay, int i) {
        AlbumStat albumStat = new AlbumStat();
        albumStat.setAlbumId(id);
        albumStat.setStatType(albumStatPlay);
        albumStat.setStatNum(i);
        albumStatMapper.insert(albumStat);
    }

}
